package cn.yuitstyle.wordtopdf;

import com.aspose.words.Document;
import com.aspose.words.FontSettings;
import com.aspose.words.MemoryFontSource;
import com.aspose.words.SaveFormat;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.IOUtils;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Modifier;
import java.util.Base64;

@Slf4j
public class PDFUtil {


    @Data
    public static class DriverAgreementTextDTO {
        private String name;

        private String context;
    }

    /**
     * 生成pdf
     *
     * @param textDTO 问题内容
     * @return 二进制输出流
     */
    public static ByteArrayOutputStream createPDF(DriverAgreementTextDTO textDTO) {
        ByteArrayOutputStream outputStream;
        try {
            InputStream resource = PDFUtil.class.getClassLoader().getResourceAsStream("ext/text.docx");
            XWPFDocument xwpfDocument = getXWPFDocument(resource);
            replaceAgreementText(xwpfDocument, textDTO);
            //二进制OutputStream
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            //文档写入流
            xwpfDocument.write(baos);
            ByteArrayInputStream is = new ByteArrayInputStream(baos.toByteArray());
            outputStream = wordToPdf(is);
        } catch (Exception e) {
            log.error("pdf转换异常", e);
            throw new RuntimeException("pdf转换异常");
        }
        return outputStream;
    }

    /**
     * 根据文档服务器路径获取文档对象
     *
     * @param fis
     * @return
     */
    public static XWPFDocument getXWPFDocument(InputStream fis) {
        XWPFDocument document;
        try {
            document = new XWPFDocument(fis);
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (Exception e) {
                    throw new RuntimeException(e.getMessage());
                }
            }
        }
        return document;
    }

    /**
     * 替换工具类
     *
     */
    public static void replaceAgreementText(XWPFDocument xwpfDocument, DriverAgreementTextDTO dto) {
        String name = dto.getName();
        if (name.length() == 2) {
            name = " " + name.charAt(0) + "  " + name.substring(1) + " ";
        } else if (name.length() == 3) {
            name = " " + name + " ";
        }
        replacePlaceholder(xwpfDocument, "{name}", name);
        replacePlaceholder(xwpfDocument, "{context}", dto.getContext());
    }

    /**
     * 替换占位符位置文本
     *
     * @param document        文档对象
     * @param placeholder     占位符
     * @param replacementText 要替换占位符的新文本
     */
    public static void replacePlaceholder(XWPFDocument document, String placeholder, String replacementText) {
        for (XWPFParagraph paragraph : document.getParagraphs()) {
            StringBuilder paragraphText = new StringBuilder();
            // 遍历段落中的每个文本片段
            for (XWPFRun run : paragraph.getRuns()) {
                String text = run.getText(0);
                if (text != null) {
                    paragraphText.append(text);
                }
            }
            // 获取段落中的文本
            String fullText = paragraphText.toString();
            // 寻找占位符位置
            int startIndex = fullText.indexOf(placeholder);
            boolean replaceText = false;
            while (startIndex >= 0) {
                // 定位到包含占位符的文本片段的位置
                int endIndex = startIndex + placeholder.length();
                // 替换占位符文本片段
                for (int i = 0; i < paragraph.getRuns().size(); i++) {
                    XWPFRun run = paragraph.getRuns().get(i);
                    String runText = run.getText(0);
                    if (runText != null) {
                        int runLength = runText.length();
                        if (startIndex < runLength && placeholder.contains(runText) && replaceText == false) {
                            replaceText = true;
                            int relativeStartIndex = Math.max(startIndex, 0);
                            int relativeEndIndex = Math.min(endIndex, runLength);
                            String newText = runText.substring(0, relativeStartIndex) + replacementText + runText.substring(relativeEndIndex);
                            run.setText(newText, 0);
                        } else if (startIndex < runLength && placeholder.contains(runText) && replaceText) {
                            run.setText("", 0);
                        }
                        startIndex -= runLength;
                        endIndex -= runLength;
                    }
                }
            }
        }
    }

    /**
     * word 转 pdf
     * @param is
     * @return
     */
    public static ByteArrayOutputStream wordToPdf(InputStream is) {
        // 验证License 若不验证则转化出的pdf文档会有水印产生
        try {
            Class<?> aClass = Class.forName("com.aspose.words.zzXyu");
            java.lang.reflect.Field zzYAC = aClass.getDeclaredField("zzZXG");
            zzYAC.setAccessible(true);

            java.lang.reflect.Field modifiersField = zzYAC.getClass().getDeclaredField("modifiers");
            modifiersField.setAccessible(true);
            modifiersField.setInt(zzYAC, zzYAC.getModifiers() & ~Modifier.FINAL);
            zzYAC.set(null, new byte[]{76, 73, 67, 69, 78, 83, 69, 68});
        } catch (Exception e) {
            log.error("apose word 破解异常");
        }

        ByteArrayOutputStream os = null;
        try {
            long old = System.currentTimeMillis();
            os = new ByteArrayOutputStream();
            // 设置字体


            // 从资源中加载字体数据
            byte[] fontData = loadFontData("fonts/simsun.ttc");

            // 创建 MemoryFontSource
            MemoryFontSource memoryFontSource = new MemoryFontSource(fontData);
            // 设置自定义字体
            FontSettings fontSettings = new FontSettings();
            fontSettings.setFontsSources(new MemoryFontSource[]{memoryFontSource});

            Document document = new Document(is);

            document.setFontSettings(fontSettings);

            document.save(os, SaveFormat.PDF);// 全面支持DOC, DOCX, OOXML, RTF HTML, OpenDocument, PDF,
            // EPUB, XPS, SWF 相互转换
            long now = System.currentTimeMillis();
            log.info("pdf转换成功，共耗时：" + ((now - old) / 1000.0) + "秒"); // 转化用时
            String s = Base64.getEncoder().encodeToString(os.toByteArray());
            log.info("bas64:" + s);
            return os;
        } catch (Exception e) {
            log.error(e.getMessage());
        } finally {
            IOUtils.closeQuietly(is);
            IOUtils.closeQuietly(os);
        }
        return os;
    }

    /**
     * 从内存中加载字体
     * @param resourcePath 字体所在目录
     */
    private static byte[] loadFontData(String resourcePath) throws IOException {
        try (InputStream inputStream = PDFUtil.class.getClassLoader().getResourceAsStream(resourcePath);
             ByteArrayOutputStream buffer = new ByteArrayOutputStream()) {
            if (inputStream == null) {
                throw new IllegalArgumentException("Resource not found: " + resourcePath);
            }
            byte[] data = new byte[1024];
            int nRead;
            while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
                buffer.write(data, 0, nRead);
            }
            return buffer.toByteArray();
        }
    }
}
